package com.company.project.util;


import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStreamReader;

@Slf4j
public class NetworkUtil {
    public static void configureLink(String containerName, String bandwidth, String delay) throws Exception {
        String command = String.format(
                "docker exec %s tc qdisc add dev eth0 root tbf rate %s burst 32kbit latency %s",
                containerName, bandwidth, delay
        );
        executeCommand(command);
    }

    public static void executeAttack(String containerId, int attackType, String targetIp) throws Exception {
        if (containerId == null || containerId.isEmpty()) {
            throw new IllegalArgumentException("Container ID cannot be null or empty");
        }

        if (targetIp == null || targetIp.isEmpty()) {
            throw new IllegalArgumentException("Target IP cannot be null or empty");
        }

        log.info("Preparing to execute attack from container {} to target {}", containerId, targetIp);

        try {
            // 检查并确保容器正在运行
            ensureContainerRunning(containerId);

            // 首先检查脚本是否存在
            String checkScriptCommand = String.format("docker exec %s ls -la /app/attack_simulator.py", containerId);
            try {
                executeCommand(checkScriptCommand);
                log.info("Attack script exists in container");
            } catch (Exception e) {
                log.error("Attack script not found in container: {}", e.getMessage());
                throw new RuntimeException("Attack script not found in container: " + e.getMessage());
            }

            String attackCommand = attackMapper(attackType, targetIp);
            if (attackCommand == null || attackCommand.isEmpty()) {
                throw new IllegalArgumentException("Invalid attack type: " + attackType);
            }

            log.info("Using attack command: {}", attackCommand);

            // 在攻击容器中执行攻击命令，确保以root用户身份运行
            String command = String.format("docker exec --privileged %s %s", containerId, attackCommand);
            log.info("Executing attack command: {}", command);

            // 使用普通的命令执行方法，等待命令完成
            executeCommand(command);

            log.info("Attack command executed successfully");
        } catch (Exception e) {
            log.error("Error executing attack: {}", e.getMessage());
            throw e;
        }
    }

    private static String attackMapper(int attackType, String targetIp) {
        /*
        docker run --rm attacker-image:latest python attack_simulator.py ddos 192.168.1.100 60
        docker run --rm attacker-image:latest python attack_simulator.py dns_poisoning 192.168.1.100 1.2.3.4
        docker run --rm attacker-image:latest python attack_simulator.py arp_spoofing 192.168.1.100 192.168.1.1
        docker run --rm attacker-image:latest python attack_simulator.py syn_flood 192.168.1.100 80
        docker run --rm attacker-image:latest python attack_simulator.py http_flood 192.168.1.100
        docker run --rm attacker-image:latest python attack_simulator.py slowloris 192.168.1.100
        docker run --rm attacker-image:latest python attack_simulator.py combined 192.168.1.100 60
        */

        // 根据Dockerfile，脚本名称是attack_simulator.py
        switch (attackType) {
            case 1:
                // DDoS攻击 - 直接执行Python脚本，不使用shell脚本包装
                return "python /app/attack_simulator.py ddos " + targetIp + " 60";
            case 2:
                // DNS投毒攻击
                return "python /app/attack_simulator.py dns_poisoning " + targetIp + " 1.2.3.4";
            case 3:
                // ARP欺骗攻击
                return "python /app/attack_simulator.py arp_spoofing " + targetIp + " 192.168.1.1";
            case 4:
                // SYN洪水攻击
                return "python /app/attack_simulator.py syn_flood " + targetIp + " 80";
            case 5:
                // HTTP洪水攻击
                return "python /app/attack_simulator.py http_flood " + targetIp;
            case 6:
                // Slowloris攻击
                return "python /app/attack_simulator.py slowloris " + targetIp;
            case 7:
                // 组合攻击
                return "python /app/attack_simulator.py combined " + targetIp + " 60";
            default:
                return "";
        }
    }

    private static void executeCommand(String command) throws Exception {
        log.info("Executing command: {}", command);

        Process process = Runtime.getRuntime().exec(command);

        // 设置命令执行超时时间（30秒）
        boolean completed = process.waitFor(65, java.util.concurrent.TimeUnit.SECONDS);

        if (!completed) {
            // 如果命令执行超时，强制终止进程
            process.destroyForcibly();
            throw new RuntimeException("Command execution timed out after 30 seconds: " + command);
        }

        // 读取标准输出
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
                log.info("executeInfo: {}", line);
            }
        }

        // 读取错误流
        StringBuilder errorOutput = new StringBuilder();
        try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
            String line;
            while ((line = errorReader.readLine()) != null) {
                errorOutput.append(line).append("\n");
                log.error("executeError: {}", line);
            }
        }

        // 检查命令执行结果
        int exitCode = process.exitValue();
        if (exitCode != 0) {
            String errorMessage = "Command execution failed: " + command;
            if (errorOutput.length() > 0) {
                errorMessage += "\nError: " + errorOutput.toString();
            }
            log.error(errorMessage);
            throw new RuntimeException(errorMessage);
        } else {
            log.info("Command executed successfully: {}", command);
        }
    }

    /**
     * 获取容器的流量信息
     * @param containerId 容器 ID
     * @return 流量信息
     * @throws Exception
     */
    public static String getTrafficInfo(String containerId) throws Exception {
        if (containerId == null || containerId.isEmpty()) {
            throw new IllegalArgumentException("Container ID cannot be null or empty");
        }

        // 使用更详细的命令获取网络流量信息
        String command = "docker exec " + containerId + " sh -c 'ifconfig eth0 && netstat -s | grep -E \"packets|segments\" && iptables -L INPUT -v -n'";
        log.info("Executing command to get traffic info: {}", command);
        Process process = Runtime.getRuntime().exec(command);

        // 读取命令输出
        StringBuilder output = new StringBuilder();
        long rxBytes = 0; // 接收字节数
        long txBytes = 0; // 发送字节数
        long rxPackets = 0; // 接收包数
        long txPackets = 0; // 发送包数
        long tcpSegments = 0; // TCP段数
        long droppedPackets = 0; // 丢弃的包数

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");

                // 提取 RX/TX 字节数和包数
                if (line.contains("RX packets")) {
                    String[] parts = line.split("\\s+");
                    for (int i = 0; i < parts.length; i++) {
                        if (parts[i].equals("packets")) {
                            rxPackets = Long.parseLong(parts[i-1]);
                        }
                    }
                } else if (line.contains("TX packets")) {
                    String[] parts = line.split("\\s+");
                    for (int i = 0; i < parts.length; i++) {
                        if (parts[i].equals("packets")) {
                            txPackets = Long.parseLong(parts[i-1]);
                        }
                    }
                } else if (line.contains("RX bytes")) {
                    String[] parts = line.split("\\s+");
                    for (int i = 0; i < parts.length; i++) {
                        if (parts[i].startsWith("bytes:")) {
                            rxBytes = Long.parseLong(parts[i].split(":")[1]);
                        } else if (parts[i].equals("bytes") && i > 0) {
                            rxBytes = Long.parseLong(parts[i-1]);
                        }
                    }
                } else if (line.contains("TX bytes")) {
                    String[] parts = line.split("\\s+");
                    for (int i = 0; i < parts.length; i++) {
                        if (parts[i].startsWith("bytes:")) {
                            txBytes = Long.parseLong(parts[i].split(":")[1]);
                        } else if (parts[i].equals("bytes") && i > 0) {
                            txBytes = Long.parseLong(parts[i-1]);
                        }
                    }
                } else if (line.contains("segments received") || line.contains("total packets received")) {
                    String[] parts = line.trim().split("\\s+");
                    if (parts.length > 0) {
                        try {
                            tcpSegments += Long.parseLong(parts[0]);
                        } catch (NumberFormatException e) {
                            // 忽略解析错误
                        }
                    }
                } else if (line.contains("dropped")) {
                    String[] parts = line.trim().split("\\s+");
                    for (int i = 0; i < parts.length; i++) {
                        if (parts[i].equals("dropped") && i > 0) {
                            try {
                                droppedPackets += Long.parseLong(parts[i-1]);
                            } catch (NumberFormatException e) {
                                // 忽略解析错误
                            }
                        }
                    }
                }
            }
        }

        // 读取错误流
        StringBuilder errorOutput = new StringBuilder();
        try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
            String line;
            while ((line = errorReader.readLine()) != null) {
                errorOutput.append(line).append("\n");
            }
        }

        if (errorOutput.length() > 0) {
            log.warn("Error output from traffic info command: {}", errorOutput.toString());
        }

        // 返回提取的流量信息
        return String.format(
            "Container ID: %s\n" +
            "RX bytes: %d (%.2f MB)\n" +
            "TX bytes: %d (%.2f MB)\n" +
            "RX packets: %d\n" +
            "TX packets: %d\n" +
            "TCP segments: %d\n" +
            "Dropped packets: %d\n" +
            "Raw output:\n%s",
            containerId,
            rxBytes, rxBytes / (1024.0 * 1024.0),
            txBytes, txBytes / (1024.0 * 1024.0),
            rxPackets,
            txPackets,
            tcpSegments,
            droppedPackets,
            output.toString()
        );
    }

    // 检查并确保容器正在运行
    private static void ensureContainerRunning(String containerId) throws Exception {
        String command = "docker inspect -f {{.State.Running}} " + containerId;
        Process process = Runtime.getRuntime().exec(command);

        // 读取命令输出
        String containerStatus = null;
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            containerStatus = reader.readLine();
        }

        // 读取错误输出
        StringBuilder errorOutput = new StringBuilder();
        try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
            String line;
            while ((line = errorReader.readLine()) != null) {
                errorOutput.append(line).append("\n");
            }
        }

        // 检查命令是否成功执行
        int exitCode = process.waitFor();
        if (exitCode != 0) {
            log.error("Failed to check container status: {}", errorOutput.toString());
            throw new Exception("Failed to check status of container " + containerId);
        }

        // 处理容器状态
        log.info("Container {} status: {}", containerId, containerStatus);

        // 检查容器是否运行中（处理各种可能的输出格式）
        boolean isRunning = containerStatus != null &&
                           (containerStatus.trim().equalsIgnoreCase("true") ||
                            containerStatus.trim().equalsIgnoreCase("'true'"));

        if (!isRunning) {
            log.info("Container {} is not running, attempting to start it...", containerId);

            // 尝试启动容器
            String startCommand = "docker start " + containerId;
            try {
                executeCommand(startCommand);
                // 等待容器启动
                Thread.sleep(2000);
                // 再次检查容器是否运行
                String checkCommand = "docker inspect -f {{.State.Running}} " + containerId;
                Process checkProcess = Runtime.getRuntime().exec(checkCommand);

                // 读取检查结果
                String checkStatus = null;
                try (BufferedReader checkReader = new BufferedReader(new InputStreamReader(checkProcess.getInputStream()))) {
                    checkStatus = checkReader.readLine();
                }

                // 检查容器是否成功启动
                boolean startedSuccessfully = checkStatus != null &&
                                             (checkStatus.trim().equalsIgnoreCase("true") ||
                                              checkStatus.trim().equalsIgnoreCase("'true'"));

                if (!startedSuccessfully) {
                    throw new Exception("Failed to start container " + containerId);
                }
                log.info("Container {} started successfully", containerId);
            } catch (Exception e) {
                log.error("Error starting container {}: {}", containerId, e.getMessage());
                throw e;
            }
        } else {
            log.info("Container {} is already running", containerId);
        }
    }

    /**
     * 验证攻击是否有效
     * @param attackerContainerId 攻击容器ID
     * @param targetContainerId 被攻击容器ID
     * @return 攻击验证结果
     * @throws Exception
     */
    public static String verifyAttack(String attackerContainerId, String targetContainerId) throws Exception {
        if (attackerContainerId == null || attackerContainerId.isEmpty()) {
            throw new IllegalArgumentException("Attacker container ID cannot be null or empty");
        }

        if (targetContainerId == null || targetContainerId.isEmpty()) {
            throw new IllegalArgumentException("Target container ID cannot be null or empty");
        }

        StringBuilder result = new StringBuilder();
        result.append("攻击验证结果：\n\n");

        // 1. 在攻击容器中验证攻击是否成功发起
        result.append("===== 攻击方验证 =====\n");
        verifyAttackerContainer(attackerContainerId, result);

        // 2. 在目标容器中验证攻击效果
        result.append("\n===== 被攻击方验证 =====\n");
        verifyTargetContainer(targetContainerId, result);

        return result.toString();
    }

    /**
     * 验证攻击容器状态
     * @param containerId 攻击容器ID
     * @param result 结果字符串构建器
     * @throws Exception
     */
    private static void verifyAttackerContainer(String containerId, StringBuilder result) throws Exception {
        // 1. 检查Python脚本是否存在
        String scriptCheckCommand = "docker exec " + containerId + " ls -la /app/attack_simulator.py 2>/dev/null || echo 'Script not found'";
        Process scriptCheckProcess = Runtime.getRuntime().exec(scriptCheckCommand);
        result.append("Python脚本检查：\n");
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(scriptCheckProcess.getInputStream()))) {
            String line;
            boolean scriptFound = false;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
                if (line.contains("attack_simulator.py")) {
                    scriptFound = true;
                }
            }
            if (!scriptFound) {
                result.append("警告：未找到攻击脚本，这可能是攻击失败的原因\n");
            }
        }
        result.append("\n");

        // 2. 检查Python是否安装
        String pythonCheckCommand = "docker exec " + containerId + " python --version";
        Process pythonCheckProcess = Runtime.getRuntime().exec(pythonCheckCommand);
        result.append("Python版本检查：\n");
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(pythonCheckProcess.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
            }
        }
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(pythonCheckProcess.getErrorStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
            }
        }
        result.append("\n");

        // 3. 检查Scapy是否安装
        String scapyCheckCommand = "docker exec " + containerId + " python -c 'import scapy; print(\"Scapy version:\", scapy.__version__)' 2>/dev/null || echo 'Scapy not installed'";
        Process scapyCheckProcess = Runtime.getRuntime().exec(scapyCheckCommand);
        result.append("Scapy检查：\n");
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(scapyCheckProcess.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
            }
        }
        result.append("\n");

        // 4. 检查容器日志
        result.append("攻击日志：\n");

        // 检查各种攻击日志文件
        String[] logFiles = {
            "/app/attack.log",
            "/app/ddos_attack.log",
            "/app/dns_attack.log",
            "/app/arp_attack.log",
            "/app/syn_attack.log"
        };

        boolean foundLogs = false;
        for (String logFile : logFiles) {
            String logCommand = "docker exec " + containerId + " cat " + logFile + " 2>/dev/null || echo ''";
            Process logProcess = Runtime.getRuntime().exec(logCommand);
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(logProcess.getInputStream()))) {
                String line;
                int lineCount = 0;
                StringBuilder logContent = new StringBuilder();

                // 读取所有行，但只保留最后10行
                String[] lastLines = new String[10];
                int index = 0;

                while ((line = reader.readLine()) != null && !line.isEmpty()) {
                    lastLines[index % 10] = line;
                    index++;
                    lineCount++;
                }

                // 如果找到日志内容
                if (lineCount > 0) {
                    foundLogs = true;
                    result.append("日志文件: ").append(logFile).append("\n");
                    result.append("最后10行内容:\n");

                    // 输出最后10行
                    int start = lineCount < 10 ? 0 : index % 10;
                    for (int i = 0; i < Math.min(10, lineCount); i++) {
                        int pos = (start + i) % 10;
                        result.append(lastLines[pos]).append("\n");
                    }
                    result.append("总日志行数: ").append(lineCount).append("\n\n");
                }
            }
        }

        if (!foundLogs) {
            result.append("未找到任何攻击日志文件，这表明攻击可能未成功执行\n\n");
        }

        // 5. 检查攻击进程是否在运行
        String psCommand = "docker exec " + containerId + " ps aux | grep -E 'attack_simulator|python' | grep -v grep";
        Process psProcess = Runtime.getRuntime().exec(psCommand);
        result.append("攻击进程状态：\n");
        boolean hasRunningAttack = false;
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(psProcess.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
                hasRunningAttack = true;
            }
        }

        if (!hasRunningAttack) {
            result.append("未发现正在运行的攻击进程，这表明攻击可能已经结束或未成功启动\n");
        }
        result.append("\n");
    }

    /**
     * 验证被攻击容器状态
     * @param containerId 被攻击容器ID
     * @param result 结果字符串构建器
     * @throws Exception
     */
    private static void verifyTargetContainer(String containerId, StringBuilder result) throws Exception {
        // 1. 检查网络连接状态
        String netstatCommand = "docker exec " + containerId + " netstat -tuln";
        Process netstatProcess = Runtime.getRuntime().exec(netstatCommand);
        result.append("网络连接状态：\n");
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(netstatProcess.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
            }
        }
        result.append("\n");

        // 2. 检查网络流量统计
        String trafficInfo = getTrafficInfo(containerId);
        result.append("网络流量统计：\n").append(trafficInfo).append("\n\n");

        // 3. 检查系统负载
        String loadCommand = "docker exec " + containerId + " sh -c 'uptime && free -m && ps aux --sort=-%cpu | head -5'";
        Process loadProcess = Runtime.getRuntime().exec(loadCommand);
        result.append("系统负载：\n");
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(loadProcess.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
            }
        }

        // 4. 检查网络连通性
        String pingCommand = "docker exec " + containerId + " ping -c 3 8.8.8.8";
        Process pingProcess = Runtime.getRuntime().exec(pingCommand);
        result.append("\n网络连通性测试：\n");
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(pingProcess.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
            }
        }
    }
}
